package com.uiao.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 代理类
 * 连接点和切点
 *
 * @author cuihao
 * @date 2018/2/28
 */

//把类声明为一个切面（1）把该类纳入到IOC容器中，（2）声明为一个切面

@Component   //1）把该类纳入到IOC容器中
@Aspect      //（2）声明为一个切面
public class LoggingAspect {
    //@Before声明该方法是一个前置通知:在目标方法之前执行
    //指定在哪些目标方法之前执行
    @Before("execution(public int com.uiao.aop.ArithmeticCalculator.*(int, int))")
    public void beforeMethod(JoinPoint joinPoint) {
        //JoinPoint
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();

        System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
    }

    //后置通知,无论连接点正常返回还是抛出异常，后置通知都会执行。
    @After("execution(public int com.uiao.aop.ArithmeticCalculator.*(int, int))")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends");
    }

    // 返回通知
    @AfterReturning(value = "execution(public int com.uiao.aop.ArithmeticCalculator.*(int, int))",
            returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends with " + result);
    }

    // 异常通知，在目标方法出现异常时参会执行的代码
    @AfterThrowing(value = "execution(public int com.uiao.aop.ArithmeticCalculator.*(int, int))",
            throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " occurs excetion:" + e);
    }

    // 环绕通知 环绕通知需要调用目标方法的执行结果，即joinPoint.proceed()的返回值
    @Around("execution(* com..Spring4.AOP.*.*(..))")
    public Object aroundMethod(ProceedingJoinPoint pjd) {

        Object result = null;
        String methodName = pjd.getSignature().getName();

        try {
            //前置通知
            System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("The method " + methodName + " ends with " + result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("The method " + methodName + " occurs exception:" + e);
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("The method " + methodName + " ends");

        return result;
    }

}

